<?php

namespace MemLib;

use \MemFrameWork\Mem;
use \MemLib\Log;
use \MemLib\Pdb;

/**
 * 缓存基类
 *
 * @version 1.0
 * @author 张云江
 */
abstract class MemBase
{
    /**
     * token键名
     */
    const mem_token = "mem_token";
    /**
     * addData后获得的临时id
     * @var mixed
     */
    private $tmp_id = 0;
    /**
     * 临时token
     * @var int
     */
    private $tmp_token = 0;
    /**
     * Mem对象
     * @var Mem
     */
    protected $memClient;
    /**
     * 缓存key,赋值格式:(表名[视图名]:要操作的字段[如果没有字段就赋表名,不包含:])
     * @var string
     */
    private $tableName;
    /**
     * redis数据库名
     * @var string
     */
    public $dbName;
    /**
     * 初始化
     * @param string $dbName  数据库名
     * @param string $tableName 表名
     */
    function __construct($dbName, $tableName)
    {
        $this->dbName = $dbName;
        $this->tableName = $tableName;
        $memclassname = MEMPROVIDE;
        $memclassname = "\\MemFrameWork\\{$memclassname}";

        $relatview = array(
            //定义视图关联表
            Pdb::db_order . ":t_order_product_info" => array(Pdb::db_order . ":t_order_application_info"),
        );
        $this->memClient = new $memclassname($relatview, $dbName, $tableName);
        if ($this->memClient->isEmptyWithConfig()) {
            if (class_exists("log")) {
                // \Mlog::info("没有找到mem缓存信息");
            }
        }
    }

    function __destruct()
    {
        $this->cleanData();
    }
    /**
     * 清理数据
     */
    private function cleanData()
    {
        if (!$this->memClient->isEmptyWithConfig())
            $this->memClient->transDel();
    }
    /**
     * 清理缓存
     */
    private function clean()
    {
        if (!$this->memClient->isEmptyWithConfig()) {
            $this->memClient->addKey();
            $this->cleanData();
        }
    }
    /**
     * 从数据库获取数据
     * @param string $sql 查询语句
     * @return array
     */
    private function getDataByDataBase($sql)
    {
        $this->tmp_token = time();
        $pdb = new Pdb($this->dbName);
        $data = $pdb->returnDataTable($sql);
        return $data;
    }
    /**
     * 执行存储过程
     * @param string $procname 存储过程名
     * @return array
     */
    private function execProcWithProcName($procname, $param)
    {
        $this->tmp_token = time();
        $pdb = new Pdb($this->dbName);
        $data = $pdb->runProcReturnTable($procname, $param);
        $this->clean();
        return $data;
    }
    /**
     * 执行存储过程
     * @param mixed $param 
     * @return array
     */
    public function execProc($param)
    {
        return $this->execProcWithProcName($this->tableName, $param);
    }
    /**
     * 添加或替换数据
     * @param array $data 数据array("字段名"=>"字段值");
     * @param bool $is_replace 是否采用replace方式操作数据
     * @return bool
     */
    public function addData($data, $is_replace = false)
    {
        $pdb = new Pdb($this->dbName);
        $ret = $pdb->AddData($this->tableName, $data, $is_replace);
        $this->clean();
        $this->tmp_id = $pdb->getAutoIncreId();
        return $ret;
    }
    /**
     * 执行操作数据更新数据，插入数据，删除数据操作(执行sql语句)
     * @param string $sql 
     * @return bool
     */
    public function execData($sql)
    {
        $pdb = new Pdb($this->dbName);
        $ret = $pdb->ExecSql($sql);
        $this->clean();
        $this->tmp_id = $pdb->getAutoIncreId();
        return $ret;
    }
    /**
     * sql分割符运算
     * @param mixed $exc 要进行分割的符号(例如:","," AND "等)
     * @param mixed $updata 要更新的数据(array("字段名"=>"数据","字段名1"=>"数据"))
     * @return string
     */
    private function linkExcision($exc, $updata)
    {
        $updatestr = "";
        if (count($updata) == 0)
            return $updatestr;
        $index = 0;
        foreach ($updata as $key => $data) {
            $key = (string)$key;
            $key = trim($key);
            if ($key == trim((string)$data))
                continue;
            $jg = $exc;
            if ($index == 0)
                $jg = "";
            $updatestr .= $jg . $key . "='{$data}'";
            $index++;
        }
        return $updatestr;
    }
    /**
     * 更新数据(条件需要自己写字段与数据对应的语句,例如:fieldname='根据我的条件' AND fieldname1='根据我的条件1')
     * @param mixed $update 要更新的字段以及数据(array("更新字段名"=>"数据","更新字段名1"=>"数据"))
     * @param string $wherestr 条件(例如:fieldname='根据我的条件' AND fieldname1='根据我的条件1')
     * @return mixed
     */
    public function updateDataWithWhere($update, $wherestr)
    {
        $sql = "UPDATE {$this->tableName} SET ";
        $updatestr = $this->linkExcision(",", $update);
        if (strlen($updatestr) == 0)
            return null;
        $sql .= $updatestr;
        if (strlen($wherestr) == 0)
            return null;
        $sql .= " WHERE " . $wherestr;
        \Mlog::info("updateSQL:" . $sql);
        return $this->execData($sql);
    }
    /**
     * 根据条件数据删除信息(array("删除字段名"=>"数据","删除字段名1"=>"数据"))
     * @param mixed $wheredata 要删除删除的数据array("删除字段名"=>"数据","删除字段名1"=>"数据")
     * @return mixed
     */
    public function deleteData($wheredata)
    {
        $where = $this->linkExcision(" AND ", $wheredata);
        return $this->deleteDataWithWhere($where);
    }
    /**
     * 根据条件删除数据
     * @param mixed $wherestr 
     * @return mixed
     */
    public function deleteDataWithWhere($wherestr)
    {
        $wherestr = (string)$wherestr;
        if (strlen($wherestr) == 0)
            return null;
        $sql = "DELETE FROM {$this->tableName} WHERE {$wherestr}";
        \Mlog::info("deleteSQL:" . $sql);
        return $this->execData($sql);
    }
    /**
     * 更新数据(该函数只有需要and条件拼接的条件时候使用)
     * @param mixed $updata 要更新的字段以及数据(array("更新字段名"=>"数据","更新字段名1"=>"数据"))
     * @param mixed $wheredata 要更新的数据的条件以及数据(array("条件字段名称"=>"条件数据","条件字段名称1"=>"条件数据")
     * 条件最后会生成filedname=data AND filename1=data AND filename2=data
     * @return mixed
     */
    public function updateData($updata, $wheredata)
    {
        $wherestr = $this->linkExcision(" AND ", $wheredata);
        return $this->updateDataWithWhere($updata, $wherestr);
    }
    /**
     * addData,execData执行后获取该函数执行获得的LAST_INSERT_ID(mysql)
     * @return mixed
     */
    public function getTmpID()
    {
        return $this->tmp_id;
    }
    /**
     * 判断token是否存在
     * @param array $data 要验证的数据
     * @param string $token 传递的token值
     * @return bool
     */
    public function isToken($token)
    {
        if ($token == $this->tmp_token)
            return true;
        return false;
    }
    /**
     * 获取上一次执行函数的token
     * @return int
     */
    public function getTmpToken()
    {
        return $this->tmp_token;
    }
    /**
     * 根据key获取缓存数据,如果没有数据将从数据库查询
     * @param string $key 
     * @return null|array
     */
    protected function getData($sql, $key)
    {
        \Mlog::info("SQL:" . $sql);
        $this->cleanData();
        if ($this->memClient->isEmptyWithConfig()) {
            $data = $this->getDataByDataBase($sql);
        } else {
            $memdata = $this->memClient->getArray($key);
            if (empty($memdata)) {
                $memdata = $this->getDataByDataBase($sql);
                //                 if(!empty($memdata)) //2018-09-26  由于空数据未保存到缓存中，因此导致多次链接数据库浪费时间而注释该条代码
                {
                    $memdata = array(
                        MemBase::mem_token => $this->tmp_token,
                        "data" => $memdata
                    );
                    $this->memClient->addArray($key, $memdata);
                }
            } else {
                $this->tmp_token = $memdata[MemBase::mem_token];
            }
            if (array_key_exists("data", $memdata)) {
                $data = $memdata["data"];
            } else {
                $data = array();
            }
        }
        return $data;
    }
    /**
     * 根据指定字段值获取相应的信息
     * @param array $list 数据集合
     * @param string $field 字段名称
     * @param mixed $value 字段值
     */
    protected static function getInfoData($list, $field, $value)
    {
        $ret = array();
        foreach ($list as $data) {
            if ($data[$field] == $value) {
                $ret[] = $data;
            }
        }
        return $ret;
    }

    /**
     * 根据id获取单条信息
     * @param mixed $id 医生id
     * @param string $fieldname 字段名称
     * @return array|null
     */
    protected function getInfo($list, $fieldname, $id)
    {
        foreach ($list as $data) {
            if (!array_key_exists($fieldname, $data))
                continue;
            if ($data[$fieldname] == $id)
                return $data;
        }
        return null;
    }
    /**
     * 刷新缓存(一般情况不要主动调用,为一些未使用该框架的程序使用)
     */
    public function flushMem()
    {
        $this->clean();
    }
    /**
     * 为列表附加symbol属性
     * @param mixed $list 要附加的列表
     * @return array
     */
    public static function addSymbolWithList($list)
    {
        $newlist = array();
        $index = 1;
        foreach ($list as $obj) {
            $obj["symbol"] = $index;
            $newlist[] = $obj;
            $index++;
        }
        return $newlist;
    }
}
